import json
import random
import re

from apps.ausers.models import User
from django.shortcuts import render
from apps.verifications import constants
from utils import response_code
from utils.response_code import RETCODE
from django.views.generic.base import View
from meiduo_mall.settings.dev import logger
from django_redis import get_redis_connection
from django.http import HttpResponse, HttpResponseForbidden, JsonResponse, HttpResponseNotFound, HttpResponseBadRequest, \
    HttpResponseNotAllowed, HttpResponseServerError


# 保存新密码
class SavePwdView(View):
    def post(self, request, user_id):
        """
        设置新密码
        :param request: 请求对象
        :param user_id: 用户ID
        :return:
        """
        """接收参数"""
        data = request.body.decode()
        data_dict = json.loads(data)
        password = data_dict.get('password')
        password2 = data_dict.get("password2")
        access_token = data_dict.get('access_token', '')
        """校验参数"""
        if not all([password, password2, access_token]):
            logger.warning('缺少必传参数，密码1、密码2、access_token')
            return HttpResponseForbidden("缺少必传参数，请从正常渠道访问")
        logger.info('新密码1为：' + str(password))
        logger.info('新密码2为：' + str(password2))
        logger.info('access_token为：' + str(access_token))
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            logger.warning('新密码格式错误，请从正常渠道访问')
            return HttpResponseForbidden('密码最少8位，最长20位')
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password2):
            logger.warning('新密码2格式错误，请从正常渠道访问')
            return HttpResponseForbidden('密码最少8位，最长20位')
        logger.info('所有密码都符合正则格式标准')
        # 2.3 判与两次新密码是否相等
        if password != password2:
            logger.warning('两次密码输入不一致，请从正常渠道访问')
            return HttpResponseForbidden('两次输入的密码不一致')
        """数据交互"""
        try:
            # 根据user_id获取用户对象
            user = User.objects.get(id=user_id)
            user.set_password(password)
            user.save()
        except Exception as err:
            logger.error('密码修改失败')
            logger.error(err)
            return HttpResponseServerError('修改密码失败')
        """返回响应"""
        return JsonResponse({'code': RETCODE.OK, 'errmg': 'OK', 'access_token': access_token})


class CheckSMSView(View):
    def get(self, request, account):
        """"""
        """接收参数"""
        # 接收手机验证码
        sms_code = request.GET.get('sms_code')
        """校验参数"""
        if not all([account, sms_code]):
            logger.warning('缺少必传参数账号或短信验证码')
            return HttpResponseForbidden('缺少必传参数，非法请求')
        """数据交互"""
        # 根据账号获取用户id
        try:
            # 去数据库查看手机号 用户名是否存在
            # 先看是不是用户名
            user = User.objects.filter(username=account)
            if user.exists():
                # 是用户名，根据用户名找手机号
                mobile = user[0].mobile
                user_id = user[0].id
            else:
                user = User.objects.filter(mobile=account)
                if user.exists():
                    mobile = user[0].mobile
                    user_id = user[0].id
                else:
                    return HttpResponseNotFound({'code': RETCODE.USERERR, 'errmsg': '账号不存在'})
        except Exception as err:
            logger.error('找回密码-检查用户名或手机号是否存在，数据库读取失败：')
            logger.error(err)
            return HttpResponseNotFound({'code': RETCODE.USERERR, 'errmsg': '账号不存在'})

        # 判断sms_code是否正确
        try:
            # 连接存放验证码的redis数据库
            redis_code_client = get_redis_connection('sms_code')
            # 根据手机号获取验证码
            redis_code = redis_code_client.get('sms_' + mobile).decode()
            # 判断数据库的验证码是否为空，有可能已经过期了
            if redis_code is None:
                logger.warning('验证码过期了')
                return HttpResponseBadRequest({'code': RETCODE.IMAGECODEERR, "errmsg": '无效的短信验证码'})
            if redis_code != sms_code:
                logger.warning('验证码有错误')
                return HttpResponseBadRequest({'code': RETCODE.IMAGECODEERR, "errmsg": '输入短信验证码有误'})
        except Exception as err:
            logger.error('获取redis数据库的验证码异常')
            logger.error(err)
            return HttpResponseServerError("获取数据库的验证码异常")

        """返回响应"""
        return JsonResponse(
            {'code': RETCODE.OK, 'errmg': 'OK', 'mobile': mobile, 'access_token': mobile, 'user_id': user_id})


# 获取短信验证码
class SMSCodeView(View):
    def get(self, request):
        """
        获取短信验证码
        :param request: 请求对象
        :return: JSON
        """
        """接收参数"""
        mobile = request.GET.get('access_token')

        """校验参数"""
        if not mobile:
            logger.warning('缺少请求参数')
            return HttpResponseForbidden("缺少请求参数，非法请求")
        """数据交互"""
        # 3、处理参数
        # 3.1 图形验证码没问题，就生成短信验证码6位的
        sms_code = "%06d" % random.randint(0, 999999)  # 10000, 999999 也行，只是第一位不能是0了就
        try:
            sms_redis_client = get_redis_connection('sms_code')
            send_flag = sms_redis_client.get('send_flag_' + mobile)
            if send_flag:
                # 如果send_flag不为空，说明60秒内才发过验证码
                return HttpResponseNotAllowed({"code": RETCODE.THROTTLINGERR, 'errmsg': '发送短信过于频繁'})
            # 如果send_flag为空，表明可以正常发送。将生成的验证码储存到Redis数据库。
            # sms_redis_client.setex('sms_' + mobile, constants.MOBILE_CODE_REDIS_EXPIRES, sms_code)
            # 并且讲send_flag也写入Redis数据库，并设置过期时间，储存内容随意
            # sms_redis_client.setex('send_flag_' + mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
            """利用pipeline操作优化与Redis数据库的交互操作"""
            # a、创建Redis管道
            pl = sms_redis_client.pipeline()
            # b、将与Redis的操作添加到管道队列
            pl.setex('sms_' + mobile, constants.IMAGE_CODE_REDIS_EXPIRES, sms_code)
            pl.setex('send_flag_' + mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
            # c、执行请求
            pl.execute()

            # 3.2 让第三方平台发送验证码
            from libs.yuntongxun import sms
            #                     手机号   验证码 有效期 短信模板号
            # sms.CCP().send_template_sms(mobile, [sms_code, 5], 1)
            # 利用Celery第三方库实现异步发送短信验证码（生产者-消费者模式）
            # from celery_tasks.sms.tasks import ccp_send_sms_code
            # ccp_send_sms_code.delay(mobile, sms_code)
            logger.info('收到的验证码是：' + sms_code)
        except Exception as err:
            logger.error('手机验证码向Redis库中保存时出错了！')
            return HttpResponseServerError('手机验证码向Redis库中保存时出错了！')

        """返回响应"""
        # 4、返回数据，告诉前段发送完毕
        return JsonResponse({'code': response_code.RETCODE.OK, 'errmsg': '发送短信成功'})


# 获取找回密码页
class FindPwdView(View):
    """获取找回密码页"""

    def get(self, request):
        """获取找回密码页"""
        return render(request, 'find_password.html')


# 校验账号是否存在，验证码是否正确
class CheckPwdView(View):
    def get(self, request, account):
        """/accounts/lifan775269525/sms/token/
        验证账号和验证码
        :param request: 请求对象
        :param account: 账号
        :return: JSON
        """
        """接收参数"""
        # account = request.GET.get('account')
        image_code = request.GET.get('text')
        uuid = request.GET.get('image_code_id')

        """校验参数"""
        if not all([account, image_code, uuid]):
            logger.warning('缺少必传参数，非法渠道访问')
            return HttpResponseForbidden("没有传入手机号，请从正常渠道访问")
        logger.info('接受到的用户名或者手机号：' + account)
        logger.info('接受到的验证码：' + image_code)
        logger.info('接受到的验证码ID：' + uuid)

        # 判断手机号号是否合法
        if (not re.match(r'^1[3-9]\d{9}$', account)) and (not re.match(r'[\w-]{5,20}', account)):
            logger.warning('账号不合法，正则的问题')
            return HttpResponseForbidden('用户名或手机号码不合法，请从正常渠道访问')

        # 判断验证码是否正确
        # 1根据UUID去redis数据库查询，图片验证码
        redis_img_code = ''
        try:
            redis_client = get_redis_connection('verify_image_code')
            redis_img_code = redis_client.get('img_' + uuid).decode()  # 注意默认取出来的是二进制
            # 2判断服务器返回的验证
            if redis_img_code is None:
                return HttpResponseBadRequest({'code': RETCODE.IMAGECODEERR, "errmsg": '图形验证码有误'})
            else:
                # 3取出值了，不管有没有值都把Redis中的图片验证码删除
                redis_client.delete('img_' + uuid)
        except Exception as err:
            logger.error('Redis数据库读取图片验证码出错')
            logger.error(err)
            return HttpResponseBadRequest({'code': RETCODE.IMAGECODEERR, "errmsg": '图形验证码有误'})

        # 4判断数据库中的图片验证码和传进来的不一样
        if image_code.lower() != redis_img_code.lower():  # 这样判断说明验证码不区分大小写
            return HttpResponseBadRequest({'code': RETCODE.IMAGECODEERR, 'errmsg': '输入图形验证码有误'})

        """数据交互"""
        try:
            # 去数据库查看手机号 用户名是否存在
            # 先看是不是用户名
            user = User.objects.filter(username=account)
            if user.exists():
                # 是用户名，根据用户名找手机号
                mobile = user[0].mobile
            else:
                user = User.objects.filter(mobile=account)
                if user.exists():
                    mobile = user[0].mobile
                else:
                    return HttpResponseNotFound({'code': RETCODE.USERERR, 'errmsg': '账号不存在'})
        except Exception as err:
            logger.error('找回密码-检查用户名或手机号是否存在，数据库读取失败：')
            logger.error(err)
            return HttpResponseNotFound({'code': RETCODE.USERERR, 'errmsg': '账号不存在'})

        """返回响应"""
        return JsonResponse({'code': RETCODE.OK, 'errmg': 'OK', 'mobile': mobile, 'access_token': mobile})
